package com.sk.photoview

import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import android.widget.OverScroller
import kotlin.math.max
import kotlin.math.min

/**
 * Create by smark
 * Time:2021/3/14
 * email:smarkwzp@163.com
 */
class PhotoView : View {
    /**
     * 图片初始默认宽度
     */
    private val IMAGE_WIDTH = Utils.dp2px(300f)
    private var bitmap: Bitmap
    private var paint: Paint
    private var originalOffsetX: Float = 0f
    private var originalOffsetY: Float = 0f

    /**
     * 最小缩放
     */
    private var smallScale: Float = 0f

    /**
     * 最大缩放
     */
    private var bigScale: Float = 0f

    /**
     * 当前缩放
     */
    private var currentScale: Float = 0f

    /**
     * 最大缩放因子
     */
    private var OVER_SCALE_FACTOR: Float = 1.5f

    /**
     * 放大后滑动偏移量X
     */
    private var scrollOffsetX: Float = 0f

    /**
     * 放大后滑动偏移量Y
     */
    private var scrollOffsetY: Float = 0f

    /**
     * 是否放大标识位
     */
    private var isEnlarge: Boolean = false

    /**
     * 普通手势管理
     */
    private var gestureDetector: GestureDetector

    /**
     * 双指缩放手势管理
     */
    private var scaleGestureDetector: ScaleGestureDetector

    /**
     * 阻尼滚动
     */
    private var overScroller: OverScroller

    /**
     * 缩放动画
     */
    private var scaleAnimator: ObjectAnimator? = null

    constructor(context: Context) : super(context)

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)

    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
        context,
        attributeSet,
        defStyleAttr
    )

    init {
        paint = Paint(Paint.ANTI_ALIAS_FLAG)
        bitmap = Utils.getPhoto(resources, IMAGE_WIDTH.toInt(), R.drawable.photo)
        gestureDetector = GestureDetector(context, PhotoViewGestureDetector())
        scaleGestureDetector = ScaleGestureDetector(context, PhotoScaleGestureListener())
        overScroller = OverScroller(context)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.let {
            val scaleFaction = (currentScale - smallScale) / (bigScale - smallScale)
            it.translate(scrollOffsetX * scaleFaction, scrollOffsetY * scaleFaction)
            it.scale(currentScale, currentScale, width / 2f, height / 2f)
            it.drawBitmap(bitmap, originalOffsetX, originalOffsetY, paint)
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        //优先处理双指事件
        var result = scaleGestureDetector.onTouchEvent(event)
        if (!scaleGestureDetector.isInProgress) {
            result = gestureDetector.onTouchEvent(event)
        }
        return result
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        originalOffsetX = (width - bitmap.width) / 2f
        originalOffsetY = (height - bitmap.height) / 2f
        if (bitmap.width.toFloat() / bitmap.height > width.toFloat() / height) {
            //横屏撑满
            smallScale = width.toFloat() / bitmap.width
            bigScale = height.toFloat() / bitmap.height * OVER_SCALE_FACTOR
        } else {
            //竖屏撑满
            smallScale = height.toFloat() / bitmap.height
            bigScale = width.toFloat() / bitmap.width * OVER_SCALE_FACTOR
        }
        currentScale = smallScale
    }

    /**
     * 获取缩放动画
     */
    private fun getScaleAnimation(): ObjectAnimator {
        if (scaleAnimator == null) {
            scaleAnimator = ObjectAnimator.ofFloat(this, "currentScale", 0f)
        }
        scaleAnimator!!.setFloatValues(smallScale, bigScale)
        return scaleAnimator!!
    }

    public fun setCurrentScale(currentScale: Float) {
        this.currentScale = currentScale
        invalidate()
    }

    public fun getCurrentScale(): Float {
        return currentScale
    }


    /**
     * 修正滑动偏移量（放大后）
     */
    private fun fixScrollOffset() {
        scrollOffsetX = min(scrollOffsetX, (bitmap.width * bigScale - width) / 2)
        scrollOffsetX = max(scrollOffsetX, -(bitmap.width * bigScale - width) / 2)
        scrollOffsetY = min(scrollOffsetY, (bitmap.height * bigScale - height) / 2)
        scrollOffsetY = max(scrollOffsetY, -(bitmap.height * bigScale - height) / 2)
    }


    /**
     * 手势实现
     */
    inner class PhotoViewGestureDetector : GestureDetector.SimpleOnGestureListener() {

        override fun onDown(e: MotionEvent?): Boolean {
            return true
        }

        override fun onFling(
            e1: MotionEvent?,
            e2: MotionEvent?,
            velocityX: Float,
            velocityY: Float
        ): Boolean {
            if (isEnlarge) {
                overScroller.fling(
                    scrollOffsetX.toInt(),
                    scrollOffsetY.toInt(),
                    velocityX.toInt(),
                    velocityY.toInt(),
                    (-(bitmap.width * bigScale - width) / 2).toInt(),
                    ((bitmap.width * bigScale - width) / 2).toInt(),
                    (-(bitmap.height * bigScale - height) / 2).toInt(),
                    ((bitmap.height * bigScale - height) / 2).toInt(),
                    300,
                    300
                )
                postOnAnimation(FlingRunner())
            }
            return super.onFling(e1, e2, velocityX, velocityY)
        }

        override fun onDoubleTap(e: MotionEvent): Boolean {
            isEnlarge = !isEnlarge
            if (isEnlarge) {
                setCurrentClickEvent(e)
                fixScrollOffset()
                getScaleAnimation().start()
            } else {
                //如果当前处于放大状态，则恢复
                if (currentScale > smallScale) {
                    if (currentScale == bigScale) {
                        getScaleAnimation().reverse()
                    } else {
                        setCurrentScale(smallScale)
                    }
                }
            }
            invalidate()
            return super.onDoubleTap(e)
        }

        override fun onScroll(
            e1: MotionEvent?,
            e2: MotionEvent?,
            distanceX: Float,
            distanceY: Float
        ): Boolean {
            if (isEnlarge) {
                scrollOffsetX -= distanceX
                scrollOffsetY -= distanceY
                fixScrollOffset()
                invalidate()
            }
            return super.onScroll(e1, e2, distanceX, distanceY)
        }
    }

    /**
     * 计算双击图片时手指与中心的偏移量实现放大后将点击区域显示在中间
     */
    private fun setCurrentClickEvent(event: MotionEvent) {
        scrollOffsetX = (event.x - width / 2f) - (event.x - width / 2f) * bigScale / smallScale
        scrollOffsetY = (event.y - height / 2f) - (event.y - height / 2f) * bigScale / smallScale
    }

    /**
     * 双指缩放事件监听
     */
    inner class PhotoScaleGestureListener : ScaleGestureDetector.OnScaleGestureListener {
        var initScale = 0f
        override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
            initScale = currentScale
            return true
        }

        override fun onScale(detector: ScaleGestureDetector?): Boolean {
            //如果没有双击放大，则不允许双指触摸放大（可以放开一下拦截代码）
//            if (!isEnlarge) {
//                return false
//            }
            if ((currentScale > smallScale && !isEnlarge)
                || (currentScale == smallScale && !isEnlarge)
            ) {
                isEnlarge = !isEnlarge;
            }
            //缩放因子
            detector?.let {
                currentScale = initScale * it.scaleFactor
                if (currentScale < smallScale) {
                    currentScale = smallScale
                }
                invalidate()
            }
            return false
        }

        override fun onScaleEnd(detector: ScaleGestureDetector?) {
        }
    }

    /**
     * 滑动惯性动画执行
     */
    inner class FlingRunner : Runnable {
        override fun run() {
            if (overScroller.computeScrollOffset()) {
                scrollOffsetX = overScroller.currX.toFloat()
                scrollOffsetY = overScroller.currY.toFloat()
                invalidate()
                //下一帧动画的时候执行
                postOnAnimation(this)
            }

        }
    }


}